package com.ib.review.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.ib.review.base.exception.ServiceException;
import com.ib.review.base.response.FileResponse;
import com.ib.review.base.response.StatusCode;
import com.ib.review.base.utils.ExcelExporter;
import com.ib.review.base.utils.MinioService;
import com.ib.review.base.utils.UploadFiles;
import com.ib.review.constant.CommonConstant;
import com.ib.review.pojo.bo.TableData;
import com.ib.review.pojo.dto.AnalyzeRecordParam;
import com.ib.review.pojo.dto.AnalyzeRecordQuery;
import com.ib.review.pojo.dto.AnalyzeResultParam;
import com.ib.review.pojo.dto.AnalyzeResultQuery;
import com.ib.review.pojo.po.AnalyzeRecordPO;
import com.ib.review.pojo.po.AnalyzeResultPO;
import com.ib.review.pojo.vo.AnalyzeRecordVO;
import com.ib.review.pojo.vo.AnalyzeResultVO;
import com.ib.review.repository.ParsingRepository;
import com.ib.review.service.ParsingService;
import com.ib.review.util.RedisUtil;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class ParsingServiceImpl implements ParsingService {

    @Resource
    private MinioService minioService;
    @Value("${minio.parse-result}")
    private String parseResult;
    @Value("${minio.folder-path}")
    private String folderPath;

    @Value("${storage-type}")
    private String storageType;

    @Resource
    private UploadFiles uploadFiles;
    @Value("${file-system.username}")
    private String username;
    @Value("${file-system.parse-create}")
    private String parseCreate;

    @Resource
    private RedisUtil redisUtil;

    private ParsingRepository parsingRepository;
    @Autowired
    private void setParsingRepository(ParsingRepository parsingRepository) {
        this.parsingRepository = parsingRepository;
    }

    public String upload(MultipartFile file, AnalyzeRecordParam param) {
        if (file.isEmpty()) {
            throw new ServiceException(StatusCode.FILE_IS_NULL);
        }

        if (!isValidFileType(file)) {
            throw new ServiceException(StatusCode.FILE_TYPE_ERROR);
        }
        String fileName = file.getOriginalFilename();
        if(fileName == null || fileName.isEmpty()){
            throw new ServiceException(StatusCode.FILENAME_ISNULL);
        }
        String userName = StpUtil.getTokenSession().getString("userAccount");
        // 校验重复文件上传
        Long count = parsingRepository.queryRecordCount(fileName,userName);
        if(count > 0){
            throw new ServiceException(StatusCode.FILE_IS_EXIST);
        }

        String fileNameUuid = param.getRecordId();
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        String filePath;
        if("1".equals(storageType)) {
            filePath = "/" + parseResult + "/" + folderPath + "/" + fileNameUuid + suffix;
            try {
                minioService.uploadFile(file,parseResult,folderPath,fileNameUuid + suffix);
            } catch (Exception e) {
                throw new ServiceException(StatusCode.MINIO_UPLOAD_FAIL);
            }
        } else {
            filePath = "/" + username + parseCreate + "/" + fileNameUuid + suffix;
            // 获取登录文件系统令牌
            String onlineID = redisUtil.get(CommonConstant.FILE_SYSTEM_LOGIN);
            if(onlineID == null || onlineID.isEmpty()){
                FileResponse fileResponse = uploadFiles.getOnlineID();
                onlineID = fileResponse.getUserOnlineID();
                Integer tokenExpireTime = fileResponse.getTokenExpireTime();
                redisUtil.setex(CommonConstant.FILE_SYSTEM_LOGIN, onlineID, tokenExpireTime-20, TimeUnit.SECONDS);
            }
            // 校验是否创建文件夹
            if(!"1".equals(redisUtil.get(CommonConstant.FILE_SYSTEM_PARSING))){
                uploadFiles.createDirectory(parseCreate,onlineID);
                redisUtil.set(CommonConstant.FILE_SYSTEM_PARSING,"1");
            }
            try {
                uploadFiles.uploadWithRestTemplate(file,filePath,onlineID);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        AnalyzeRecordPO po = new AnalyzeRecordPO();
        po.setRecordId(fileNameUuid);
        po.setFileName(fileName);
        po.setFileType(suffix.toLowerCase());
        po.setFilePath(filePath);
        po.setStatus(0);
        po.setCreator(userName);
        LocalDateTime now = LocalDateTime.now().withNano(0);
        Date dateWithoutMillis = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
        po.setCreateTime(dateWithoutMillis);
        po.setModifier(userName);
        po.setModifyTime(dateWithoutMillis);
        po.setDelFlag(0);
        po.setStartNum(param.getStartNum());
        po.setEndNum(param.getEndNum());
        po.setModeType(param.getModeType());
        parsingRepository.insertRecord(po);
        return fileNameUuid;
    }

    public List<AnalyzeRecordPO> queryRecord(AnalyzeRecordQuery analyzeRecordQuery) {
        // 直接计算三天前的时间，去除纳秒部分
        LocalDateTime threeDaysAgo = LocalDateTime.now().minusDays(2).withNano(0);
        String fileName = null;
        if (analyzeRecordQuery != null) {
            fileName = analyzeRecordQuery.getFileName();
        }
        String userName = StpUtil.getTokenSession().getString("userAccount");
        return parsingRepository.selectByTimeRange(threeDaysAgo,fileName,userName);
    }

    public void deleteRecord(AnalyzeResultQuery analyzeResultQuery) {
        parsingRepository.deleteRecord(analyzeResultQuery.getRecordId());
    }

    public List<AnalyzeResultVO> queryResult(AnalyzeResultQuery analyzeResultQuery) {
        List<AnalyzeResultPO> po = parsingRepository.selectByRecordId(analyzeResultQuery);
        return po.stream().map(this::convertToVO).collect(Collectors.toList());
    }

    public void updateResult(AnalyzeResultParam analyzeResultParam) {
        parsingRepository.updateResult(analyzeResultParam);
    }

    public AnalyzeRecordVO queryRecordById(AnalyzeRecordQuery analyzeRecordQuery) {
        AnalyzeRecordPO po = parsingRepository.queryRecordById(analyzeRecordQuery);
        Long resultNum = parsingRepository.queryResultCount(analyzeRecordQuery.getRecordId());
        AnalyzeRecordVO vo = new AnalyzeRecordVO();
        BeanUtils.copyProperties(po,vo);
        vo.setResultNum(resultNum);
        return vo;
    }

    public byte[] exportToExcel(String recordId) {
        List<String> list = parsingRepository.exportToExcel(recordId);
        List<TableData> tables = new ArrayList<>();
        for (String s : list) {
            // 使用FastJSON解析成JSONArray
            JSONArray jsonArray = JSON.parseArray(s);
            // 取出第一个元素并转成目标对象
            if (!jsonArray.isEmpty()) {
                TableData tableData = jsonArray.getObject(0, TableData.class);
                tables.add(tableData);
            }
        }
        byte[] bytes;
        try {
            bytes = ExcelExporter.exportTablesToExcel(tables);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return bytes;
    }

    private AnalyzeResultVO convertToVO(AnalyzeResultPO resultPO) {
        AnalyzeResultVO resultVO = new AnalyzeResultVO();
        BeanUtils.copyProperties(resultPO,resultVO);
        return resultVO;
    }

    private boolean isValidFileType(MultipartFile file) {
        // 允许的文件扩展名
        String[] allowedExtensions = {".jpeg", ".jpg", ".gif", ".png", ".bmp", ".pdf"};
        // 允许的Content-Type
        String[] allowedContentTypes = {
                "image/jpeg", "image/jpg", "image/gif",
                "image/png", "image/bmp", "application/pdf"
        };

        String originalFilename = file.getOriginalFilename();
        String contentType = file.getContentType();

        // 检查文件扩展名
        boolean isExtensionValid = false;
        if (originalFilename != null) {
            String lowerFileName = originalFilename.toLowerCase();
            for (String extension : allowedExtensions) {
                if (lowerFileName.endsWith(extension)) {
                    isExtensionValid = true;
                    break;
                }
            }
        }

        // 检查Content-Type
        boolean isContentTypeValid = false;
        if (contentType != null) {
            for (String type : allowedContentTypes) {
                if (contentType.equalsIgnoreCase(type)) {
                    isContentTypeValid = true;
                    break;
                }
            }
        }
        return isExtensionValid && isContentTypeValid;
    }
}
